package 极客时间.concurrence.并发编程实战篇.读写锁;

import java.time.temporal.ValueRange;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author idea
 * @Date created in 8:38 上午 2020/7/29
 */
public class Cache<K, V> {

    private HashMap<K, V> hashMap = new HashMap<>();

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    private volatile boolean cacheValid = true;

    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();

    public void put(K key, V val) {
        writeLock.lock();
        try {
            hashMap.put(key, val);
        } finally {
            writeLock.unlock();
        }
    }


    public V getV2(K key){
        V val;
        readLock.lock();
        try {
            val = hashMap.get(key);
            if(val!=null){
                return val;
            }
        }finally {
            readLock.unlock();
        }
        if(!cacheValid){
            writeLock.lock();
            try {
                val = hashMap.get(key);
                cacheValid = true;
            }finally {
                writeLock.unlock();
            }
        }
        return val;
    }

    /**
     * 错误写法，这种写法是
     * @param key
     * @return
     */
    public V getV1(K key) {
        readLock.lock();
        try {
            V val = hashMap.get(key);
            if (val == null) {
                val = queryFromDB(key);
                //读写锁是不支持升级操作的，从读锁升级为了写锁会导致线程一直处于堵塞状态
                writeLock.lock();
                try {
                    val = hashMap.get(key);
                } finally {
                    writeLock.unlock();
                }
            }
            return val;
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 查询数据库
     *
     * @param key
     */
    public V queryFromDB(K key){
        System.out.println("查询数据库");
        cacheValid = false;
        return null;
    }


}
